#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <string>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <vector>
#include <iostream>
#include <limits>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <sys/shm.h>
#include "config.h"

using namespace std;

static int addIEEEOpt(void);
static vector<string> argvector;

/**
 * int 转 string
 */
string itos(int i)
{
	stringstream s;
	s<<i;
	return s.str();
}


int main (int argc, char *argv[]) {
	// sec表示间隔多少秒检查SYNC文件
	// 如果SYNC文件的内容为1，需启动ptp程序，如果SYNC文件内容为0，停止ptp程序
	int sec=20;
	int i, fd, sync;
	FILE *sync_fp = NULL, *ptpflag_fp = NULL;
	string mode, mode_tmp;
	pid_t pid = -1;
	int shmid;
	int *ptpflag = 0;//ptpflag用来标志ptp程序是否正在运行

	/*
	 * 以下代码段类似cleanlog.cpp的共享存储代码段，注释请参考那边
	 * */
	key_t shmkey;
	shmkey = ftok(PTP_FLAG_FILE, 0);
	if ((shmid = shmget(shmkey, SHM_SIZE, SHM_MODE|IPC_CREAT)) < 0) perror("shmget error");
	if ((ptpflag = (int *)shmat(shmid, 0, 0)) == (int *)-1) perror("shmat error");

	mode_tmp = get_config("Mode");
	//网卡接口操作
	if ( !(fd = open(DEVICE_NAME,O_RDWR|O_NDELAY)) ) exit(1);
	if ( mode_tmp.compare("1") == 0 || mode_tmp.compare("3") == 0 )
		ioctl(fd,MODE_SET,PTP_MODE);
	else if ( mode_tmp.compare("2") == 0  || mode_tmp.compare("4") == 0 )
		ioctl(fd,MODE_SET,ETE_MODE);
	close(fd);
	while(1){
		sleep(sec); //休眠sec时间
		/*以下操作对Peer-to-Peer和End-to-End进行处理，调用的是dp83640_driver里边的文件接口*/
		mode = get_config("Mode");
		if(mode_tmp.compare(mode) != 0){
			// 侦测到ptp运行的模式需要改变（用户通过telnet修改了模式，因为要立即生效，不要重启生效，所以程序需要重启ptp程序）
			// 则需要将改变告诉驱动程序，让其重设模式，同时，需要让ptp程序重启
			if( mode.empty())
				cout << "				Can't get mode from Config.xml" << endl;
			else {
				//驱动程序接口操作
				if ( !(fd = open(DEVICE_NAME,O_RDWR|O_NDELAY)) ) exit(1);
				if ( mode.compare("1") == 0 || mode.compare("3") == 0 )
					ioctl(fd,MODE_SET,PTP_MODE);
				else if ( mode.compare("2") == 0  || mode.compare("4") == 0 )
					ioctl(fd,MODE_SET,ETE_MODE);
				close(fd);
				mode_tmp = mode;
				if(*ptpflag == 1 ) { //表示ptp程序正在运行，需要kill掉
					//ptp进程是以该进程的子进程运行的，于是可以直接通过kill系统调用杀死
					if( kill(pid,SIGKILL) < 0)	//使用kill系统调用杀死子进程
						perror("kill error");
					else {
						*ptpflag = 0;
					}
				}
			}
		}
		if((sync_fp=fopen(SYNC_FILE,"r"))==NULL){
			perror("open file error");
			continue;
		}else sync=getc(sync_fp);
		fclose(sync_fp);

		//父进程通过设置SIGCHLD信号的handler为SIG_IGN，显式的忽略了SIGCHLD信号，
		//使其子进程在退出过程中也可能不会保留它的task_struct
		if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
			perror("signal error");

		if(sync == '1' && *ptpflag == 0){
			//以下操作启动ptp子进程
			if ((pid = vfork()) < 0) {	//vfork不完全复制父进程的地址空间的内容，所以这边使用vfork,以改变父进程的ptpflag变量
				perror("fork error");	//vfork失败
			} else if(pid == 0){	//子进程
				*ptpflag = 1;	//ptp程序启动成功，设置ptpflag为1,把ptpflag语句放在execv之前是因为如果execv()函数执行正确，那么其后面的代码是不会执行的

				//设置命令参数，需要将用户传递给父进程的参数原封不动的传递给ptp子进程
				argvector.clear();
				argvector.push_back("ptpd2");
				for(i = 1; i < argc; i++) argvector.push_back(argv[i]);
				addIEEEOpt();

				const int arg_size = argvector.size();
				char *args[arg_size];
				for (i = 0; i < arg_size; i++) args[i] = const_cast<char *>(argvector[i].c_str());
				//使用execv启动ptp程序
				if (execv("./", args) == -1){	//ptp程序启动失败
					perror("execv error");
					*ptpflag = 0;	//启动失败，需要更改ptpflag为0
					continue;
				}
			} else {	//父进程不做处理
				//printf("child pid:%d\n",pid);
				//printf("parent ptpflag:%d.\n",ptpflag);
			}
		}

		if(sync == '0' && *ptpflag == 1){	//SYNC文件中的数据为0并且ptp程序正在运行，需要将ptp程序kill掉
			if( kill(pid,SIGKILL) < 0)	//使用kill系统调用杀死子进程
				perror("kill error");
			else {
				*ptpflag = 0;	//	ptp程序不在运行
			}
		}
	}

	//free share memory
	if (shmdt(ptpflag) < 0) perror("shmdt error");
	if (shmctl(shmid, IPC_RMID, NULL) < 0) perror("shmctl error");
	exit(0);
}

/**
 * 添加ptp子进程参数
 */
static int addIEEEOpt(void)
{
	//argvector.push_back("-u");	//	默认使用单播模式
	string s;
	//	send包频率
	if( !(s = get_config("Frequency")).empty() ) {
		argvector.push_back("-y");
		argvector.push_back(s);
	}

	//	Peer-to-Peer or End-to-End
	string mode = get_config("Mode");
	if( mode.empty())
		cout << "				Can't get mode from Config.xml" << endl;
	else{
		if ( mode.compare("2") == 0  || mode.compare("4") == 0 )
			argvector.push_back("-h");	//	run in End to End mode
		if ( mode.compare("1") == 0 || mode.compare("2") == 0 )
			argvector.push_back("-e");	// run in 802.3
	}

	return 0;
}
